package leetcode.pre1000;

import java.util.Arrays;

/**
 * 美团面试题
 * 给定一个整数数组 A，
 * <p>
 * 返回其中元素之和可被 K 整除的（连续、非空）子数组的中最长连续子数组。
 * <p>
 * <p>
 * 示例：
 * <p>
 * 输入：A = [4,5,0,-2,-3,1], K = 5
 * 输出：[4, 5, 0, -2, -3, 1]
 * 解释：
 * 有 7 个子数组满足其元素之和可被 K = 5 整除：
 * [4, 5, 0, -2, -3, 1], [5], [5, 0], [5, 0, -2, -3],
 * [0], [0, -2, -3], [-2, -3]
 * <p>
 * 其他见{@link leetcode.a_总结分布.Code07_数组子数组问题}
 * TODO 剩余定理  时间O(n)
 * @date 2020/5/24 18:09
 */
public class Code974_和可被K整除的子数组2 {
    public static void main(String[] args) {
        int []A = {4,5,0,-2,-3,1};
        int k = 5;
        int[] ints = process1(A, k);
        System.out.println(Arrays.toString(ints));
        ints = process2(A, k);
        System.out.println(Arrays.toString(ints));
    }
    /**
     * 方式1：暴力遍历所有
     */
    public static int[] process1(int[]nums,int k){
        if(nums == null || nums.length == 0){
            return null;
        }
        int left = 0;
        int right = 0;
        for (int i = 0; i < nums.length; i++) {
            int sum = 0;
            for (int j = i; j < nums.length; j++) {
                sum += nums[j];
                if((sum % k) == 0 && j - i > right - left){
                    left = i;
                    right = j;
                }
            }
        }
        if(right == 0) return null;
        return Arrays.copyOfRange(nums,left,right+1);
    }

    /**
     * 方式2：动态规划
     * dp[i][j]表示从i到j的连续子序列的和
     * 其中 j >= i
     * dp[i][j] = dp[i][j-1] + nums[j]
     * dp[i][i] = nums[i],
     */
    public static int[] process2(int[]nums,int k) {
        if (nums == null || nums.length == 0) {
            return null;
        }
        int[][]dp = new int[nums.length][nums.length];
        int left= 0;
        int right = -1;
        for (int i = 0; i < nums.length; i++) {
            dp[i][i] = nums[i];
            if(dp[i][i] % k == 0 && right == -1){
                left = right = i;
            }
            //j >= i,j<i没有意义
            for (int j = i + 1; j < nums.length; j++) {
                dp[i][j] = dp[i][j-1] + nums[j];
                if(dp[i][j] % k == 0 && j - i > right - left){
                    left = i;
                    right = j;
                }
            }
        }
        return right == -1 ? null : Arrays.copyOfRange(nums,left,right+1);
    }
}
